// const HtmlWebpackPlugin = require('html-webpack-plugin') // * html 插件
const ESLintPlugin = require('eslint-webpack-plugin') // * eslint 插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // * 提取 css 插件
const TerserPlugin = require('terser-webpack-plugin') // * 用于压缩 JavaScript，webpack5 自带且默认开启
// const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin') // * 图片压缩插件
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin')

const path = require('path')

const os = require('os')

// * cpu 核心数
const cpus = os.cpus().length

const getStyleLoader = (pres = []) => {
  return [
    { loader: MiniCssExtractPlugin.loader },
    { loader: 'css-loader' },
    { loader: 'postcss-loader' },
    ...pres
  ]
}

module.exports = {
  // * 单入口文件
  entry: './src/main.js', // * 相对路径
  // * 多入口文件
  // entry: {
  //   main: './src/main.js',
  //   app: './src/app.js'
  // },
  output: {
    // publicPath: './',
    // * __dirname nodeJs 变量，代表当前文件的文件夹路径
    path: path.resolve(__dirname, '../dist'), // * 绝对路径
    // * 入口文件打包输出路径
    filename: 'js/[name]-[contenthash:10].js',
    chunkFilename: 'js/[name]-chunk.[contenthash:10].js',
    // * asset 模块输出路劲
    assetModuleFilename: 'media/[hash:10][ext][query]',
    // * 自动清空上次打包内容
    clean: true
  },
  module: {
    rules: [
      {
        // * oneOf 仅进行一次匹配
        oneOf: [
          {
            test: /\.css$/,
            use: getStyleLoader()
          },
          {
            test: /\.less$/,
            use: getStyleLoader([{ loader: 'less-loader' }])
          },
          {
            test: /\.s[ac]ss$/i,
            use: getStyleLoader([{ loader: 'sass-loader' }])
          },
          {
            test: /\.styl$/i,
            use: getStyleLoader([{ loader: 'stylus-loader' }])
          },
          // * loader 的配置
          {
            test: /\.(png|svg|jpg|jpeg|gif)$/i,
            type: 'asset'
          },
          {
            test: /\.(woff|woff2|eot|ttf|otf)$/i,
            type: 'asset/resource'
          },
          {
            test: /\.tpl$/,
            use: [
              'babel-loader',
              {
                loader: './loaders/demo/tpl-loader',
                options: {
                  log: true
                }
              }
            ]
          },
          {
            // * babel
            test: /\.js$/,
            exclude: /(node_modules|bower_components)/,
            use: [
              {
                loader: 'thread-loader',
                options: {
                  // * 产生的 worker 数量，默认为cup核心数 - 1
                  workers: cpus
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  // * Babel 配置可新建 babel.config.js 配置
                  // presets: ['@babel/preset-env']
                  // ! cacheDirectory 和 cacheCompression 为 webpack 对于 babel-loader 的特有选项
                  // * 开启Babel缓存，提高每次 rebuild 速度
                  cacheDirectory: true,
                  // * 开启时会进行缓存压缩，减少磁盘占有量
                  // * 关闭缓存压缩，提高 rebuild 速度
                  cacheCompression: false,
                  // * 'transform-runtime' 插件告诉 Babel
                  // * 要引用 runtime 来代替注入，减少重复定义的代码量
                  plugins: ['@babel/plugin-transform-runtime']
                }
              }
            ]
          }
        ]
      }
    ]
  },
  plugins: [
    // * 插件的配置
    new ESLintPlugin({
      // * 需要检测的文件目录
      context: path.resolve(__dirname, '../src'),
      cache: true,
      // * 默认 catch 路径为 .eslintcache
      cacheLocation: path.resolve(
        __dirname,
        '../node_modules/.cache/eslintcache'
      ),
      threads: cpus // * 以线程池方式运行 lint
    }),
    new MiniCssExtractPlugin({
      // * 提取单独的css文件
      filename: 'css/[contenthash].css',
      chunkFilename: 'css/chunk-[name][contenthash:10].css'
    }),
    new PreloadWebpackPlugin({
      // rel: 'prefetch'
      rel: 'preload'
      // as: 'script'
    })
  ],
  optimization: {
    // * 优化类配置
    minimizer: [
      // * https://webpack.docschina.org/configuration/optimization/#optimizationminimizer
      new TerserPlugin({
        // * 多进程并发运行以提高构建速度
        parallel: cpus
      })
      // // * 图片压缩插件
      // new ImageMinimizerPlugin({
      //   minimizer: {
      //     implementation: ImageMinimizerPlugin.imageminGenerate,
      //     options: {
      //       plugins: [
      //         ['gifsicle', { interlaced: true }],
      //         ['jpegtran', { progressive: true }],
      //         ['optipng', { optimizationLevel: 5 }],
      //         [
      //           'svgo',
      //           {
      //             plugins: [
      //               'preset-default',
      //               'prefixIds',
      //               {
      //                 name: 'sortAttrs',
      //                 params: {
      //                   xmlnsOrder: 'alphabetical'
      //                 }
      //               }
      //             ]
      //           }
      //         ]
      //       ]
      //     }
      //   }
      // })
    ],
    splitChunks: {
      chunks: 'all' // 对所有模块都进行分割
      // 以下是默认值
      // minSize: 20000, // 分割代码最小的大小
      // minRemainingSize: 0, // 类似于minSize，最后确保提取的文件大小不能为0
      // minChunks: 1, // 至少被引用的次数，满足条件才会代码分割
      // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
      // maxInitialRequests: 30, // 入口js文件最大并行请求数量
      // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包（此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests）
      // cacheGroups: { // 组，哪些模块要打包到一个组
      //   defaultVendors: { // 组名
      //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
      //     priority: -10, // 权重（越大越高）
      //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块，则它将被重用，而不是生成新的模块
      //   },
      //   default: { // 其他没有写的配置会使用上面的默认值
      //     minChunks: 2, // 这里的minChunks权重更大
      //     priority: -20,
      //     reuseExistingChunk: true,
      //   },
      // },
      // 修改配置
      // cacheGroups: {
      //   // 组，哪些模块要打包到一个组
      //   // defaultVendors: { // 组名
      //   //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
      //   //   priority: -10, // 权重（越大越高）
      //   //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块，则它将被重用，而不是生成新的模块
      //   // },
      //   default: {
      //     // 其他没有写的配置会使用上面的默认值
      //     minSize: 0, // 我们定义的文件体积太小了，所以要改打包的最小文件体积
      //     minChunks: 1,
      //     priority: -20,
      //     reuseExistingChunk: true
      //   }
      // }
    },
    runtimeChunk: {
      name: entrypoint => `runtime~${entrypoint.name}`
    }
  }
}
